using System.Text.Json;
using Microsoft.Extensions.Logging;
using CollabApp.Application.Interfaces;
using CollabApp.Domain.Services.Game;

namespace CollabApp.Application.Services.Game;

/// <summary>
/// 游戏广播服务实现 - 基于Redis的企业级实现
/// 负责游戏事件的实时广播和消息分发
/// </summary>
public class GameBroadcastService : IGameBroadcastService
{
    private readonly IRedisService _redisService;
    private readonly ILogger<GameBroadcastService> _logger;

    public GameBroadcastService(
        IRedisService redisService,
        ILogger<GameBroadcastService> logger)
    {
        _redisService = redisService ?? throw new ArgumentNullException(nameof(redisService));
        _logger = logger ?? throw new ArgumentNullException(nameof(logger));
    }

    /// <summary>
    /// 广播游戏状态更新
    /// 向所有游戏参与者推送游戏状态的变化
    /// </summary>
    public async Task<bool> BroadcastGameStateUpdateAsync(Guid gameId, GameStateUpdate stateUpdate)
    {
        try
        {
            _logger.LogInformation("广播游戏状态更新 - GameId: {GameId}, Status: {Status}", 
                gameId, stateUpdate.Status);

            var broadcastData = new
            {
                Type = "GameStateUpdate",
                GameId = stateUpdate.GameId,
                Status = stateUpdate.Status.ToString(),
                Timestamp = stateUpdate.Timestamp,
                RemainingTime = stateUpdate.RemainingTime?.TotalSeconds,
                Round = stateUpdate.Round,
                StateData = stateUpdate.StateData
            };

            await StoreBroadcastMessageAsync(gameId, "GameStateUpdate", broadcastData);
            
            _logger.LogDebug("游戏状态更新广播成功 - GameId: {GameId}, Status: {Status}", 
                gameId, stateUpdate.Status);
            return true;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "广播游戏状态更新失败 - GameId: {GameId}", gameId);
            return false;
        }
    }

    /// <summary>
    /// 广播玩家行为
    /// 向其他玩家推送某个玩家的行为信息
    /// </summary>
    public async Task<bool> BroadcastPlayerActionAsync(Guid gameId, PlayerActionBroadcast playerAction, Guid? excludePlayerId = null)
    {
        try
        {
            _logger.LogDebug("广播玩家行为 - GameId: {GameId}, PlayerId: {PlayerId}, ActionType: {ActionType}", 
                gameId, playerAction.PlayerId, playerAction.ActionType);

            var actionData = new
            {
                Type = "PlayerAction",
                PlayerId = playerAction.PlayerId,
                PlayerName = playerAction.PlayerName,
                ActionType = playerAction.ActionType.ToString(),
                Position = playerAction.Position,
                TargetPosition = playerAction.TargetPosition,
                TargetPlayerId = playerAction.TargetPlayerId,
                Timestamp = playerAction.Timestamp,
                ActionData = playerAction.ActionData,
                ExcludePlayerId = excludePlayerId
            };

            await StoreBroadcastMessageAsync(gameId, "PlayerAction", actionData);
            return true;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "广播玩家行为失败 - GameId: {GameId}, PlayerId: {PlayerId}", 
                gameId, playerAction.PlayerId);
            return false;
        }
    }

    /// <summary>
    /// 广播游戏事件
    /// 推送重要的游戏事件给相关玩家
    /// </summary>
    public async Task<bool> BroadcastGameEventAsync(Guid gameId, GameEventBroadcast gameEvent, List<Guid>? targetPlayers = null)
    {
        try
        {
            _logger.LogInformation("广播游戏事件 - GameId: {GameId}, EventType: {EventType}", 
                gameId, gameEvent.EventType);

            var eventMessage = new
            {
                Type = "GameEvent",
                EventType = gameEvent.EventType,
                Title = gameEvent.Title,
                Message = gameEvent.Message,
                Priority = gameEvent.Priority.ToString(),
                RelatedPlayerId = gameEvent.RelatedPlayerId,
                Location = gameEvent.Location,
                Timestamp = gameEvent.Timestamp,
                EventData = gameEvent.EventData,
                TargetPlayers = targetPlayers
            };

            await StoreBroadcastMessageAsync(gameId, "GameEvent", eventMessage);
            return true;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "广播游戏事件失败 - GameId: {GameId}, EventType: {EventType}", 
                gameId, gameEvent.EventType);
            return false;
        }
    }

    /// <summary>
    /// 发送私人消息
    /// 向特定玩家发送私人消息或通知
    /// </summary>
    public async Task<bool> SendPrivateMessageAsync(Guid gameId, Guid playerId, PrivateMessage message)
    {
        try
        {
            _logger.LogDebug("发送私人消息 - GameId: {GameId}, TargetPlayerId: {PlayerId}", gameId, playerId);

            var privateMessageData = new
            {
                Type = "PrivateMessage",
                GameId = gameId,
                TargetPlayerId = playerId,
                SenderId = message.SenderId,
                SenderName = message.SenderName,
                Content = message.Content,
                MessageType = message.MessageType.ToString(),
                Timestamp = message.Timestamp
            };

            // 使用特定的私人消息键存储
            var messageKey = $"private_message:{playerId}:{Guid.NewGuid()}";
            await _redisService.StringSetAsync(messageKey, JsonSerializer.Serialize(privateMessageData), 
                TimeSpan.FromHours(24));

            _logger.LogDebug("私人消息发送成功 - GameId: {GameId}, TargetPlayerId: {PlayerId}", 
                gameId, playerId);
            return true;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "发送私人消息失败 - GameId: {GameId}, PlayerId: {PlayerId}", gameId, playerId);
            return false;
        }
    }

    /// <summary>
    /// 广播计分更新
    /// 推送计分变化和排名更新
    /// </summary>
    public async Task<bool> BroadcastScoreUpdateAsync(Guid gameId, ScoreUpdateBroadcast scoreUpdate)
    {
        try
        {
            _logger.LogInformation("广播计分更新 - GameId: {GameId}, PlayerCount: {Count}", 
                gameId, scoreUpdate.PlayerScores.Count);

            var scoreData = new
            {
                Type = "ScoreUpdate",
                GameId = scoreUpdate.GameId,
                PlayerScores = scoreUpdate.PlayerScores?.Select(p => new
                {
                    PlayerId = p.PlayerId,
                    PlayerName = p.PlayerName,
                    PreviousScore = p.PreviousScore,
                    CurrentScore = p.CurrentScore,
                    ScoreChange = p.ScoreChange,
                    Reason = p.Reason
                }).ToList<object>() ?? new List<object>(),
                Rankings = scoreUpdate.Rankings?.Select(r => new
                {
                    PlayerId = r.PlayerId,
                    PlayerName = r.PlayerName,
                    Rank = r.Rank,
                    Score = r.Score
                }).ToList<object>() ?? new List<object>(),
                Timestamp = DateTime.UtcNow
            };

            await StoreBroadcastMessageAsync(gameId, "ScoreUpdate", scoreData);
            return true;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "广播计分更新失败 - GameId: {GameId}", gameId);
            return false;
        }
    }

    /// <summary>
    /// 广播地图更新
    /// 推送游戏地图或环境的变化
    /// </summary>
    public async Task<bool> BroadcastMapUpdateAsync(Guid gameId, MapUpdateBroadcast mapUpdate)
    {
        try
        {
            _logger.LogInformation("广播地图更新 - GameId: {GameId}, UpdateType: {UpdateType}", 
                gameId, mapUpdate.UpdateType);

            var mapData = new
            {
                Type = "MapUpdate",
                GameId = mapUpdate.GameId,
                UpdateType = mapUpdate.UpdateType.ToString(),
                Timestamp = mapUpdate.Timestamp
            };

            await StoreBroadcastMessageAsync(gameId, "MapUpdate", mapData);
            return true;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "广播地图更新失败 - GameId: {GameId}", gameId);
            return false;
        }
    }

    /// <summary>
    /// 广播玩家状态更新
    /// 推送玩家状态的实时变化
    /// </summary>
    public async Task<bool> BroadcastPlayerStatusUpdateAsync(Guid gameId, PlayerStatusUpdate statusUpdate)
    {
        try
        {
            _logger.LogDebug("广播玩家状态更新 - GameId: {GameId}, PlayerId: {PlayerId}", 
                gameId, statusUpdate.PlayerId);

            var statusData = new
            {
                Type = "PlayerStatusUpdate",
                PlayerId = statusUpdate.PlayerId,
                PlayerName = statusUpdate.PlayerName,
                Position = statusUpdate.Position,
                Health = statusUpdate.Health,
                Timestamp = statusUpdate.Timestamp
            };

            await StoreBroadcastMessageAsync(gameId, "PlayerStatusUpdate", statusData);
            return true;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "广播玩家状态更新失败 - GameId: {GameId}, PlayerId: {PlayerId}", 
                gameId, statusUpdate.PlayerId);
            return false;
        }
    }

    /// <summary>
    /// 广播系统通知
    /// 发送系统级别的重要通知
    /// </summary>
    public async Task<bool> BroadcastSystemNotificationAsync(Guid gameId, SystemNotification notification, List<Guid>? targetPlayers = null)
    {
        try
        {
            _logger.LogInformation("广播系统通知 - GameId: {GameId}, Type: {NotificationType}", 
                gameId, notification.Type);

            var notificationData = new
            {
                Type = "SystemNotification",
                NotificationType = notification.Type.ToString(),
                Title = notification.Title,
                Message = notification.Message,
                Priority = notification.Priority.ToString(),
                Timestamp = notification.Timestamp,
                TargetPlayers = targetPlayers
            };

            await StoreBroadcastMessageAsync(gameId, "SystemNotification", notificationData);
            return true;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "广播系统通知失败 - GameId: {GameId}", gameId);
            return false;
        }
    }

    /// <summary>
    /// 加入游戏房间
    /// 将玩家连接加入到特定的游戏房间，建立实时通信
    /// </summary>
    public async Task<bool> JoinGameRoomAsync(string connectionId, Guid gameId, Guid playerId)
    {
        try
        {
            _logger.LogInformation("玩家加入游戏房间 - GameId: {GameId}, PlayerId: {PlayerId}, ConnectionId: {ConnectionId}", 
                gameId, playerId, connectionId);

            // 使用Redis存储连接映射关系
            var connectionKey = $"game_connection:{connectionId}";
            var connectionData = new
            {
                GameId = gameId,
                PlayerId = playerId,
                JoinTime = DateTime.UtcNow
            };

            await _redisService.StringSetAsync(connectionKey, JsonSerializer.Serialize(connectionData), 
                TimeSpan.FromHours(24));

            // 添加到游戏房间的在线玩家列表
            var gamePlayersKey = $"game_players:{gameId}";
            await _redisService.HashSetAsync(gamePlayersKey, connectionId, playerId.ToString());

            return true;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "加入游戏房间失败 - GameId: {GameId}, PlayerId: {PlayerId}, ConnectionId: {ConnectionId}", 
                gameId, playerId, connectionId);
            return false;
        }
    }

    /// <summary>
    /// 离开游戏房间
    /// 将玩家连接从游戏房间移除，清理相关资源
    /// </summary>
    public async Task<bool> LeaveGameRoomAsync(string connectionId, Guid gameId, Guid playerId)
    {
        try
        {
            _logger.LogInformation("玩家离开游戏房间 - GameId: {GameId}, PlayerId: {PlayerId}, ConnectionId: {ConnectionId}", 
                gameId, playerId, connectionId);

            // 移除连接映射
            var connectionKey = $"game_connection:{connectionId}";
            await _redisService.KeyDeleteAsync(connectionKey);

            // 从游戏房间玩家列表中移除
            var gamePlayersKey = $"game_players:{gameId}";
            await _redisService.HashDeleteAsync(gamePlayersKey, connectionId);

            return true;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "离开游戏房间失败 - GameId: {GameId}, PlayerId: {PlayerId}, ConnectionId: {ConnectionId}", 
                gameId, playerId, connectionId);
            return false;
        }
    }

    /// <summary>
    /// 获取在线玩家列表
    /// 返回当前游戏中的在线玩家信息
    /// </summary>
    public async Task<List<OnlinePlayer>> GetOnlinePlayersAsync(Guid gameId)
    {
        try
        {
            var onlinePlayers = new List<OnlinePlayer>();
            var gamePlayersKey = $"game_players:{gameId}";
            
            var playerConnections = await _redisService.GetHashAllAsync(gamePlayersKey);
            
            foreach (var connection in playerConnections)
            {
                try
                {
                    if (Guid.TryParse(connection.Value, out var playerId))
                    {
                        var onlinePlayer = new OnlinePlayer
                        {
                            PlayerId = playerId,
                            ConnectionId = connection.Key
                        };
                        onlinePlayers.Add(onlinePlayer);
                    }
                }
                catch (Exception ex)
                {
                    _logger.LogWarning(ex, "解析在线玩家数据失败 - GameId: {GameId}, Connection: {Connection}", 
                        gameId, connection.Key);
                }
            }

            _logger.LogDebug("获取在线玩家列表成功 - GameId: {GameId}, Count: {Count}", 
                gameId, onlinePlayers.Count);
            return onlinePlayers;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "获取在线玩家列表失败 - GameId: {GameId}", gameId);
            return new List<OnlinePlayer>();
        }
    }

    #region 私有辅助方法

    /// <summary>
    /// 存储广播消息到Redis
    /// 统一的消息存储和分发机制
    /// </summary>
    private async Task StoreBroadcastMessageAsync(Guid gameId, string messageType, object messageData)
    {
        try
        {
            // 创建唯一的消息键
            var messageKey = $"game_broadcast:{gameId}:{messageType}:{Guid.NewGuid()}";
            var serializedMessage = JsonSerializer.Serialize(messageData);
            
            // 存储消息内容，30分钟过期
            await _redisService.StringSetAsync(messageKey, serializedMessage, TimeSpan.FromMinutes(30));
            
            // 添加到广播消息队列，用于客户端轮询或推送服务处理
            var queueKey = $"game_message_queue:{gameId}";
            var queueItem = new
            {
                MessageKey = messageKey,
                MessageType = messageType,
                Timestamp = DateTime.UtcNow
            };
            
            await _redisService.StringSetAsync($"{queueKey}:{DateTime.UtcNow.Ticks}", 
                JsonSerializer.Serialize(queueItem), TimeSpan.FromHours(1));
            
            _logger.LogDebug("广播消息存储成功 - GameId: {GameId}, MessageType: {MessageType}, Key: {MessageKey}", 
                gameId, messageType, messageKey);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "存储广播消息失败 - GameId: {GameId}, MessageType: {MessageType}", 
                gameId, messageType);
            throw;
        }
    }

    #endregion
}
